package Utils;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import java.util.Objects;
import java.util.Set;

public class MyScanner extends ClassPathBeanDefinitionScanner {

//  注意 java基础问题 如果父类没有默认的构造器  子类必须显示的调用父类某个构造器
//  因为在实例化子类时会自动调用父类构造器实例化父类
    public MyScanner(BeanDefinitionRegistry registry) {
        super(registry);
    }

//    由于Spring的Component扫描不会扫描接口 但是我们这里模拟的是扫描 MyBatis中的DAO接口 所以需要手动实现
    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition)  {
//        修改Spring原本判断逻辑 让她对接口才判断是合法Component
        return beanDefinition.getMetadata().isInterface();
    }
//  扫描只负责得到BeanDefinition  不会实例化对象
    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        for (BeanDefinitionHolder beanDefinitionHolder : beanDefinitionHolders) {
            GenericBeanDefinition beanDefinition = (GenericBeanDefinition) beanDefinitionHolder.getBeanDefinition();

//        给FactoryBean中的构造器赋值  注意 这里是先给构造器赋值再改BeanClass   是因为我们拿到的是接口的BeanDefinition对象
//            我们需要将FactoryBean中的的Class属性先赋值 再改为FactoryBean类型  否则接口的Class对象会丢失
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(Objects.requireNonNull(beanDefinition.getBeanClassName()));
            beanDefinition.setBeanClass(MyFactoryBean.class);
//            在获取到beanDefinition之后我们可以设置自动注入模式  设置完之后就可以在set方法中不用注解就可以自动注入
            beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);

        }
        return beanDefinitionHolders;
    }
}
